home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 16021 < prev    next >
Encoding:
Internet Message Format  |  1996-08-05  |  6.6 KB

  1. Path: keats.ugrad.cs.ubc.ca!not-for-mail
  2. From: c2a192@ugrad.cs.ubc.ca (Kazimir Kylheku)
  3. Newsgroups: comp.lang.ada,comp.lang.c,comp.lang.c++,comp.edu
  4. Subject: Re: ANSI C and POSIX (was Re: C/C++ knocks the crap out of Ada)
  5. Date: 8 Apr 1996 22:31:40 -0700
  6. Organization: Computer Science, University of B.C., Vancouver, B.C., Canada
  7. Message-ID: <4kcsnsINNgkb@keats.ugrad.cs.ubc.ca>
  8. References: <JSA.96Feb16135027@organon.com> <dewar.828936837@schonberg> <4kb2j8$an0@solutions.solon.com> <dewar.829011320@schonberg>
  9. NNTP-Posting-Host: keats.ugrad.cs.ubc.ca
  10.  
  11. In article <dewar.829011320@schonberg>, Robert Dewar <dewar@cs.nyu.edu> wrote:
  12. >Peter said
  13. >
  14. >"How?  No offense meant, but any code which can be affected by this is flat
  15. >out broken.  POSIX-style read is to be given a pointer to at least nbytes
  16. >of space, for the information read.  Period."
  17. >
  18. >That's really confusing, the code in question DID give a buffer large
  19. >enough to hold nbytes of data, where nbytes is the number of bytes 
  20. >for "the information read". Maybe I don't understand, but reading the
  21. >above sentence, it sounds like you would be surprised by the Linux
  22. >behavior.
  23. >
  24. >Here is the exact case. We declare a buffer of 100 bytes. We read a
  25. >1000 bytes from a file whose total length is 68 bytes. On all systems
  26. >that we had experience with other than Linux, this worked fine, the
  27. >first 68 bytes of the buffer is filled, and the remaining 32 bytes
  28. >is unused. 
  29.  
  30. This is poor coding. You are _advertizing_ a buffer of size 1000, but passing a
  31. pointer to a 100 byte buffer. It wouldn't even occur to me to do this, and
  32. until now I have been completely oblivious to this difference between Linux and
  33. other systems.
  34.  
  35. Unfortunately, I could not find anything in POSIX.1 that would explicitly
  36. disallow this. The document is not very assertive in defining undefined
  37. behavior. I'm going to check it once again in case I missed something.
  38.  
  39. I checked the manual pages for read() on several systems. Linux documents that
  40. EFAULT results if the buffer pointed at by buf is outside of the address space
  41. of the process. On other systems, it is claimed that EFAULT results if the buf
  42. pointer is directed outside of the address space.
  43.  
  44. >I am not claiming this is "correct" code in some abstract sense. I
  45. >certainly can't tell that it is wrong from the definitions I have
  46. >of the read function. What I am claiming is that this worked on
  47. >all systems we tried it on, and then failed on Linux. I am not saying
  48. >Linux is wrong here, just that its behavior was surprising!
  49.  
  50. It's not surprising: you lied to the read() function. But you are right, you
  51. can't tell this from the definition in POSIX.1 or from typical manual pages.
  52. There are certain unwritten rules, though!
  53.  
  54. >The code in question made 100% sure that the data read would never
  55. >exceed the buffer size, and I would have been hard pressed to
  56. >determine that the code was incorrect. 
  57.  
  58. Really? What if another process appended data to the file before you got to the
  59. end? A simple script running as the same user ID as the program would always
  60. have the right permissions to do this, provided the file in question is not a
  61. temporary file that was unlinked before being written.
  62.  
  63. What prevented the code from advertizing the true buffer size of 100?
  64.  
  65. Can we see this code, along with some of its context?
  66.  
  67. In any case, it doesn't sound like a case of ``defensive programming''.
  68.  
  69. >I am not sure that POSIX is relevant here, almost none of the systems on
  70. >which we ran claimed POSIX compliance. Peter, can you post the POSIX
  71. >wording on read, I don't have it at hand. Does it in fact make it
  72. >clear that the Linux behavior is correct and that the program was
  73. >wrong.
  74.  
  75. The POSIX.1 wording on read() doesn't get into anything that is remotely
  76. helpful in this discussion at all. In fact, the whole document is only an
  77. interface specifiction that basically tells you how these functions are called
  78. and what are their semantics, and minimal error conditions.
  79.  
  80. >Let's suppose that the POSIX standard does in fact make it clear that
  81. >the Linux behavior is correct. I still think the check is unwise
  82.  
  83. I checked the POSIX.1 document and it does not make it clear. The importance of
  84. the EFAULT checks is downplayed, and I could not find a definite statement
  85. in the document that passing illegal arguments even leads to undefined behavior.
  86. There is a gaping lack of a comprehensive list of what constitutes non-portable
  87. or illegal use of the functions, as far as I could tell.
  88.  
  89. >(note that the check is not against the actual size of the buffer
  90. >given, this is of course impossible in C, it is against the end
  91. >of the address range of the data area). It's a good example of the
  92. >kind of principle I mentioned before. Since almost all systems allow
  93. >the program I described above to work correctly, and it is manifestly
  94. >safe programming evenif the check is not present, I think it would
  95. >be a better choice for Linux not to do this extra check.
  96.  
  97. And allow kernel code to potentially make an illegal reference to a not present
  98. page? I'd rather not have it that way just to fix the extremely rare buggy
  99. program. Perhaps checking the bounds just for the actual data transferred might
  100. be better. But this would complicate the kernel code.  It's easy to check the
  101. buffer first, immediately upon entry into the read() system call, when it is
  102. not known how many bytes will be read from the given file or device.  From
  103. there, control can pass to any of a number of subsystems  via a function
  104. pointer in the f_op structure of the file node.  Since the check is done at the
  105. entry point, the individual read() functions of various filesystem modules and
  106. device drivers can confidently use the entire buffer without having to do their
  107. own check after determining the actual transfer size.  IMHO, requiring the
  108. individual read functions to do their own checking would result in
  109. unnecessary complication, when it it so easy and obvious to do a comprehensive
  110. check in the central sys_read() dispatcher! When working on a new device
  111. driver, I wouldn't want to mess around with details that should be taken care
  112. for me.
  113.  
  114. If you want an example of behavior that is unequivocally ``different'', look no
  115. further than the Linux select() call. Unlike what happens on other UNIXes, the
  116. Linux select() system call modifies the timeval structure. Code that depends on
  117. the structure not being modified will break. This tripped me up, and caused
  118. some fairly prominent programs to behave differently (including some versions
  119. of the Mosaic web browser, which used select() as a delay mechanism. The little
  120. globe picture would spin like crazy, since Mosaic assumed that the delay values
  121. were preserved for multiple invocations of select rather than decremented down
  122. to nothing!)
  123. -- 
  124.  
  125.